/**
 * Created by SCR on 2017/7/19.
 */
// 数据驱动的模型集成

// 这里所有的MSID都是MSInstanceID，只有运行时传过去的那个才是真正的MSID

var SysCtrl = require('../sysControl');
var RmtReqCtrl = require('../remoteReqControl');
var AggreSolutionModel = require('../../model/Integrate/aggreSolution');
var AggreTaskModel = require('../../model/Integrate/aggreTask');
var setting = require('../../setting');
var GeoDataCtrl = require('../geoDataControl');
var ModelSerControl = require('../modelSerControl');
var ModelIns = require('../../model/modelInstance');
var ModelSerModel = require('../../model/modelService');
var ModelSerRunCtrl = require('../modelSerRunControl');
var ModelSerRunModel = require('../../model/modelSerRun');
var NoticeCtrl = require('../noticeCtrl');
var uuid = require('node-uuid');
var WebSocketCtrl = require('./WebSocketCtrl');
var TaskInstanceManager = require('../../model/Integrate/TaskInstanceManager');
var CommonMethod = require('../../utils/commonMethod');

var Path = require('path');
var fs = require('fs');
var ObjectId = require('mongodb').ObjectID;
var qs = require('querystring');
var uuid = require('node-uuid');

// 状态和角色分开存
const DataState = {
    // unready: 'UNREADY',      // DataState表示的是已经上传过的数据的状态，没有 unready这一种
    ready: 'READY',             // 准备好，表示初始状态，将要分发的状态，before dispatch
    pending: 'PENDING',         // 正在传输 dispatching
    received: 'RECEIVED',       // 计算节点接受成功 after dispatch
    failed: 'FAILED'            // 计算节点接受失败 failed
    // mid: 'MID',                 // 计算中间产物
    // result: 'RESULT'            // 输出数据的状态，是最终计算结果数据（没有流向下个模型） is result
    // used: 'USED'                // 模型已经跑完，使用过该数据 is used

};

const TaskState = {
    configured: 'CONFIGURED',
    running: 'RUNNING',
    end: 'END',
    finished: 'FINISHED',
    collapsed: 'COLLAPSED',
    pause: 'PAUSE'
};

const MSState = {
    unready: 'UNREADY',         // 初始状态，前台创建task时默认是这种
    pending: 'PENDING',         // 正在发送运行指令
    pause: 'PAUSE',             // 允许用户给准备好的模型打断点
    collapsed: 'COLLAPSED',     // 运行失败，两种情况：调用出错；运行失败
    running: 'RUNNING',         // 现在默认准备好数据就开始运行
    finished: 'FINISHED'        // 运行成功且结束
};

global.DataState = DataState;
global.TaskState = TaskState;
global.MSState = MSState;

module.exports = (function () {

    var __getServiceStates = function (service) {
        return service.MDL.ModelClass.Behavior.StateGroup.States.State;
    };

    var __getServiceEvents = function (service) {
        let eventList = [];
        if(service.serviceType == ServiceType.model){
            let states = __getServiceStates(service);
            if(states instanceof Array){

            }
            else{
                states = [states];
            }
            for(let i=0;i<states.length;i++){
                let state = states[i];
                let stateID = state._$.id;
                let stateName = state._$.name;
                let stateDes = state._$.description;
                let events = state.Event;
                if(events instanceof Array){

                }
                else{
                    events = [events];
                }

                for(let j=0;j<events.length;j++){
                    events[j].stateID = stateID;
                    events[j].stateName = stateName;
                    events[j].stateDes = stateDes;
                    eventList.push(events[j]);
                }
            }
        }
        // else if(service.serviceType == ServiceType.dataMap){
        //     let state = service.CDL.StateGroup.States[0];
        //     for(let i=0;i<state.Events.length;i++){
        //
        //     }
        // }
        // else if(service.serviceType == ServiceType.dataRefactor){
        //
        // }
        return eventList;
    };

    // 判断一个模型的输出数据是否是作为另一个模型的输入
    var __get2NodesEvent = function (solution, MSID, stateID, eventName) {
        var relationList = solution.solutionCfg.relationList;
        var toNodes = [];
        for(let i=0;i<relationList.length;i++){
            var fromNode = relationList[i].from;
            if(fromNode.MSID == MSID && fromNode.stateID == stateID && fromNode.eventName == eventName){
                toNodes.push(relationList[i].to);
            }
        }
        return toNodes;
    };

    var __getFromNodeEvent = function (solution, MSID, stateID, eventName) {
        var relationList = solution.solutionCfg.relationList;
        for(let i=0;i<relationList.length;i++){
            var toNode = relationList[i].to;
            if(toNode.MSID == MSID && toNode.stateID == stateID && toNode.eventName == eventName){
                return relationList[i].from;
            }
        }
        return null;
    };

    var __getServiceDriver = function (taskID, MSinsID) {
        var serviceDriver = {
            ready: true,
            inputData: [],
            outputData: []
        };

        var task = TaskInstanceManager.get(taskID);
        var uploadDataList = task.taskCfg.dataList;
        var solution = task.solution;
        var serviceList = solution.solutionCfg.serviceList;
        var service = null;
        for(let i=0;i<serviceList.length;i++){
            if(serviceList[i]._id == MSinsID){
                service = serviceList[i];
                break;
            }
        }
        if(service == null){
            serviceDriver.ready = false;
            return serviceDriver;
        }

        var MSStateList = task.MSState;
        for(let i=0;i<MSStateList.length;i++){
            if(MSStateList[i].MSID == MSinsID && MSStateList[i].state != MSState.unready){
                serviceDriver.ready = false;
                return serviceDriver;
            }
        }

        var states = __getServiceStates(service);
        if(states instanceof Array){

        }
        else {
            states = [states];
        }
        var events = __getServiceEvents(service);

        if(service.MS.ms_model.m_name == 'HydroResponseUnitGenerator'){
            console.log(1);
        }
        for(let i=0;i<states.length;i++){
            var state = states[i];
            var stateID = state._$.id;
            var stateName = state._$.name;
            var stateDes = state._$.description;
            for(let i=0;i<events.length;i++){
                var event = events[i];
                if(event.stateID != stateID){
                    continue;
                }

                if(events[i]._$.type == 'response'){
                    var hasInserted = false;
                    var isOptional = event._$.optional;
                    isOptional = CommonMethod.isTrue(isOptional);
                    // 根据用户是否已经上传数据判断是不是计算驱动的数据
                    for(let j=0;j<uploadDataList.length;j++){
                        var uploadData = uploadDataList[j];
                        if(event._$.name == uploadData.eventName){
                            console.log(uploadData.eventName);
                        }
                        if( MSinsID == uploadData.MSID &&
                            stateID == uploadData.stateID &&
                            event._$.name == uploadData.eventName){
                            if(uploadData.state == DataState.received){
                                serviceDriver.inputData.push({
                                    DataId: uploadData.gdid,
                                    Event: event._$.name,
                                    Optional: isOptional? 1: 0,
                                    StateId: stateID,
                                    StateName: stateName,
                                    StateDes: stateDes
                                });
                                hasInserted = true;
                                break;
                            }
                            else{
                                serviceDriver.ready = false;
                                return serviceDriver;
                            }
                        }
                    }

                    // 根据箭头指向判断是不是计算驱动的数据
                    if(!hasInserted){
                        var fromNode = __getFromNodeEvent(solution, MSinsID, stateID, event._$.name);
                        if(fromNode){
                            serviceDriver.ready = false;
                            return serviceDriver;
                        }
                        else {
                            if (isOptional) {
                                serviceDriver.inputData.push({
                                    DataId: '',
                                    Event: event._$.name,
                                    Optional: 1,
                                    StateId: stateID,
                                    StateName: stateName,
                                    StateDes: stateDes
                                });
                            }
                            else {
                                serviceDriver.ready = false;
                                return serviceDriver;
                            }
                        }
                    }
                }
                else if(events[i]._$.type == 'noresponse'){
                    serviceDriver.outputData.push({
                        StateName: stateName,
                        StateDes: stateDes,
                        StateId: stateID,
                        Event: event._$.name,
                        Tag: ''
                    });
                }
            }
        }

        return serviceDriver;
    };

    // region deprecated
    // 恢复任务
    // 场景
    // 运算结果数据可能没加入进来，这样就没有数据驱动task继续运行下去
    var __restoreTaskScene = function (task) {
        var msStateList = task.MSState;
        AggreSolutionModel.getByOID(task.taskCfg.solutionID,function (err, solution) {
            if(err){
                WebSocketCtrl.emit(taskID,'error',JSON.stringify({error:err}));
            }
            else{
                for(let i=0;i<msStateList.length;i++){
                    if(msStateList[i].state == MSState.finished){
                        __restoreServiceScene(task, solution, msStateList[i].MSID);
                    }
                }

            }
        });
    };

    var __restoreServiceScene = function (task, solution, MSID) {
        var service = null;
        var serviceList = solution.solutionCfg.serviceList;
        var dataList = task.taskCfg.dataList;
        for(let i=0;i<serviceList.length;i++){
            if(serviceList[i]._id == MSID){
                service = serviceList[i];
            }
        }
        if(service){
            var events = __getServiceEvents(service);
            for(let i=0;i<events.length;i++){
                var event = events[i];
                var hasInserted = false;
                for(let j=0;j<dataList.length;j++){
                    if(dataList[j].MSID == MSID && dataList[j].stateID == event.stateID && event._$.name){
                        hasInserted = true;
                    }
                }
            }
        }
    };
    // endregion

    return {
        // 以模型为入口，查找模型依赖的输入数据，驱动数据分发和模型运算
        init: function (task) {
            var self = this;
            var MSStateList = task.MSState;
            for(let i=0;i<MSStateList.length;i++){
                if(MSStateList[i].state == MSState.unready){
                    var MSID = MSStateList[i].MSID;
                    var serviceDataList = [];
                    var taskDataList = task.taskCfg.dataList;
                    for(let j=0;j<taskDataList.length;j++){
                        if(taskDataList[j].MSID == MSID && taskDataList[j].state == DataState.ready){
                            serviceDataList.push(taskDataList[j]);
                        }
                    }
                    this.dispatchDataListPosition(task._id,MSID,serviceDataList);
                }
                else{
                    MSStateList[i].taskStateFlag = 1;
                }
            }
            TaskInstanceManager.update(task, function (err, rst) {
                if(err){

                }
                else{
                    // self.checkTaskState(task._id);
                }
            });
        },

        checkTaskState: function (taskID) {
            var self = this;
            var task = TaskInstanceManager.get(taskID);
            for(let i=0;i<task.MSState.length;i++){
                if(task.MSState[i].taskStateFlag != 1){
                    return ;
                }
            }

            for(let i=0;i<task.MSState.length;i++){
                task.MSState[i].taskStateFlag = 0;
            }

            var MSStateList = task.MSState;
            var hasRunning = false;
            var hasCollapsed = false;
            var hasPause = false;
            var hasUnready = false;
            var hasFinished = false;
            var hasPending = false;
            var pauseStates = [];

            for(let i=0;i<MSStateList.length;i++){
                var state = MSStateList[i].state;
                var MSID = MSStateList[i].MSID;
                if(state == MSState.collapsed){
                    hasCollapsed = true;
                }
                else if(state == MSState.running){
                    hasRunning = true;
                    break;
                }
                else if(state == MSState.finished){
                    hasFinished = true;
                }
                else if(state == MSState.pause){
                    hasPause = true;
                    pauseStates.push(MSID);
                }
                else if(state == MSState.unready){
                    hasUnready = true;
                }
                else if(state == MSState.pending){
                    hasPending = true;
                    break;
                }
            }

            // var detail = null;
            var taskState = null;
            if(hasRunning || hasPending){
                taskState = TaskState.running;
            }
            // TODO 崩溃的逻辑不太对
            else if(hasCollapsed){
                taskState = TaskState.collapsed;
            }
            else if(hasUnready && !hasPause){
                taskState = TaskState.end;
            }
            else if(hasUnready && hasPause){
                // 状态可能是end pause，看unready的state在pause之前还是之后
                // 如果所有pause的service的状态都是准备好的，task的状态就是pause，否则是end
                let isAllMSReady = true;
                for(let i=0;i<pauseStates.length;i++){
                    if(!self.checkMSState(task._id,null,pauseStates[i],true)){
                        isAllMSReady = false;
                        break;
                    }
                }
                if(isAllMSReady){
                    taskState = TaskState.pause;
                }
                else {
                    taskState = TaskState.end;
                }
            }
            else{
                if(hasPause){
                    taskState = TaskState.pause;
                }
                else{
                    taskState = TaskState.finished;
                }
            }

            task.taskState = taskState;
            TaskInstanceManager.updateByID(task._id,function (err, rst) {
                if(err){
                    WebSocketCtrl.emit(task._id,'update task state',JSON.stringify({
                        error: err,
                        taskState: taskState
                    }));
                }
                else{
                    if(taskState == TaskState.collapsed ||
                        taskState == TaskState.end ||
                        taskState == TaskState.finished ||
                        taskState == TaskState.pause){
                        WebSocketCtrl.emit(task._id,'update task state',JSON.stringify({
                            error: null,
                            taskState: taskState
                            // detail:
                        }));
                    }

                    if(taskState == TaskState.end ||
                        taskState == TaskState.finished){
                        // TaskInstanceManager.delete(task._id,function (err, rst) {
                        //
                        // });
                    }
                }
            });
        },

        // 分两种驱动：未分发完数据的由数据驱动，已分发完数据的直接检查模型准备状态
        // 分发数据坐标，更新数据状态为pending
        // 返回一个数组，[{error:Object}]，通过websocket传给前台
        dispatchDataListPosition: function (taskID,MSID,dataList) {
            var dispatchRst = [];
            var count = 0;
            // __restoreTaskScene(task);

            // 不需要输入数据的模型
            if(dataList.length == 0){
                this.checkMSState(taskID,null,MSID);
                return;
            }
            for(let i=0;i<dataList.length;i++){
                // 只分发ready状态的数据
                if(dataList[i].state == DataState.ready){
                    dispatchRst.push({
                        gdid: dataList[i].gdid,
                        MSID: dataList[i].MSID,
                        stateID: dataList[i].stateID,
                        eventName: dataList[i].eventName,
                        posType: dataList[i].posType,
                        host: dataList[i].host,
                        port: dataList[i].port,
                        error:null
                    });
                    this.__emitDataPosition(taskID, dataList[i],(function (i) {
                        count++;
                        return function (err){
                            count--;
                            if(err){
                                dispatchRst[i].error = err;
                                err.place = '__emitDataPosition';
                            }
                            if(count == 0){
                                // 更新数据状态
                                TaskInstanceManager.updateDataListState(taskID, dispatchRst, function (err, rst) {
                                    if(err){
                                        err.place = 'updateDataListState';
                                    }
                                    WebSocketCtrl.emit(taskID,'data dispatched', JSON.stringify({error:err,dispatchRst:dispatchRst}))
                                });
                            }
                        }
                    })());
                }
            }
        },

        // 分发数据坐标，更新数据状态
        __emitDataPosition: function (taskID, taskData, cb) {
            var self = this;
            var MSID = taskData.MSID;
            var task = TaskInstanceManager.get(taskID);
            var serviceList = task.solution.solutionCfg.serviceList;
            var serviceHost = servicePort = serviceType = null;
            for(let i=0;i<serviceList.length;i++){
                if(serviceList[i]._id == MSID){
                    serviceHost = serviceList[i].host;
                    servicePort = serviceList[i].port;
                    serviceType = serviceList[i].serviceType;
                    break;
                }
            }

            if(serviceHost && servicePort){
                var form = {
                    // taskID: taskID,
                    // MSID: taskData.MSID,
                    // stateID: taskData.stateID,
                    // eventName: taskData.eventName,
                    gdid: taskData.gdid,
                    host: taskData.host,
                    port: taskData.port,
                    posType: taskData.posType
                };
                var url = null;
                if(serviceType == ServiceType.model){
                    url = 'http://' + serviceHost + ':' + servicePort + '/integration/onReceivedDataPosition';
                    RmtReqCtrl.postByServer(url,form,function (err, res) {
                        if(err){
                            // TODO 重新尝试
                            return cb(err);
                        }
                        else{
                            self.getDownloadRst(taskID,taskData);
                            return cb(null);
                        }
                    });
                }
                else if(serviceType == ServiceType.dataMap || serviceType == ServiceType.dataRefactor){
                    url = 'http://' + serviceHost + ':' + servicePort + '/user/remoteUserData';
                    form.username = 'admin';
                    form.fname = taskData.fname;
                    form.oid = taskData.oid;
                    switch (taskData.posType){
                        case DataPositionType.local:
                            form.posType = 'LOCAL';
                            break;
                        case DataPositionType.dataservice:
                            form.posType = 'DATA_SERVICE';
                            break;
                        case DataPositionType.modelservice:
                            form.posType = 'MODEL_SERVICE';
                            break;
                    }
                    RmtReqCtrl.getByServer(url,form,function (err, res) {
                        if(err){
                            // TODO 重新尝试
                            return cb(err);
                        }
                        else{
                            self.getDownloadRst(taskID,taskData);
                            return cb(null);
                        }
                    })
                }

            }
            else{
                return cb(new Error('Can\'t find relative service!'));
            }
        },

        // region model container
        // 保留
        // 拿到数据坐标，下载数据并添加到数据库中
        // TODO 下载失败信息存哪
        // TODO 数据容器增加这个功能
        onReceivedDataPosition: function (dataPosition) {
            var self = this;
            var url = null;
            if(dataPosition.posType == 'LOCAL'){
                url = 'http://' + dataPosition.host + ':' + dataPosition.port + '/geodata/detail/' + dataPosition.gdid;
            }
            else if(dataPosition.posType == 'MODEL SERVICE'){
                url = 'http://' + dataPosition.host + ':' + dataPosition.port + '/geodata/detail/' + dataPosition.gdid;
            }
            else if(dataPosition.posType == 'DATA SERVICE'){
                url = 'http://' + dataPosition.host + ':' + dataPosition.port + '/user/download?filename=' + dataPosition.oid;
            }
            // 先查询有没有
            GeoDataCtrl.exist(dataPosition.gdid,function (err, exist) {
                if (err) {

                }
                else {
                    if (exist) {

                    }
                    else {
                        // 请求数据
                        new Promise(function (resolve, reject) {
                            RmtReqCtrl.getByServer(url,null,function (err, res) {
                                if(err){
                                    return reject(err);
                                }
                                else {
                                    return resolve(JSON.parse(res));
                                }
                            })
                        })
                            // 保存数据
                            .then(function (gd) {
                                return new Promise(function (resolve, reject) {
                                    if(gd.error){
                                        reject(new Error(gd.error));
                                    }
                                    if(gd.gd_type == 'FILE'){
                                        var path = Path.join(__dirname,'../../geo_data/' + dataPosition.gdid);
                                        fs.writeFile(path,gd.gd_value,function (err) {
                                            if (err) {
                                                return reject(err);
                                            }
                                            else{
                                                gd.gd_value = dataPosition.gdid + '.xml';
                                                GeoDataCtrl.addData(gd,function (err, rst) {
                                                    if(err){
                                                        return reject(err);
                                                    }
                                                })
                                            }
                                        });
                                    }
                                    else if(gd.gd_type == 'STREAM'){
                                        GeoDataCtrl.addData(gd,function (err, rst) {
                                            if(err){
                                                return reject(err);
                                            }
                                        })
                                    }
                                })
                            })
                            .catch(function (err) {
                                console.log(err);
                            })
                    }
                }
            });
        },
        // endregion

        // 轮询请求
        // TODO 让进哥开接口，不能通过下载来判断是否下载完成，要不然遇到大数据会浪费网络资源
        getDownloadRst: function (taskID, taskData) {
            var self = this;
            var MSID = taskData.MSID;
            var task = TaskInstanceManager.get(taskID);
            var serviceList = task.solution.solutionCfg.serviceList;
            var serviceHost = servicePort = serviceType = null;
            for (let i = 0; i < serviceList.length; i++) {
                if (serviceList[i]._id == MSID) {
                    serviceHost = serviceList[i].host;
                    servicePort = serviceList[i].port;
                    serviceType = serviceList[i].serviceType;
                    break;
                }
            }

            if (serviceHost && servicePort) {
                var url = null;
                if(serviceType == ServiceType.model){
                    url = 'http://' + serviceHost + ':' + servicePort + '/geodata/exist/' + taskData.gdid;
                }
                else if(serviceType == ServiceType.dataMap){
                    url = 'http://' + serviceHost + ':' + servicePort + '/user/download?username=admin&filename=' + taskData.oid;
                }
                else if(serviceType == ServiceType.dataRefactor){
                    url = 'http://' + serviceHost + ':' + servicePort + '/user/download?username=admin&filename=' + taskData.oid;
                }

                var polling = function () {
                    RmtReqCtrl.getByServer(url, null,function (err, res) {
                        if(err){
                            // TODO
                        }
                        else{
                            if(serviceType == ServiceType.model){
                                res = JSON.parse(res);
                                if(res.exist){
                                    self.onReceivedDataDownloaded(taskID, taskData);
                                }
                                else{
                                    setTimeout(polling,5000);
                                }
                            }
                            else if(serviceType == ServiceType.dataMap){
                                if(res.indexOf('this is not a file.') != -1){
                                    setTimeout(polling,5000);
                                }
                                else{
                                    self.onReceivedDataDownloaded(taskID, taskData);
                                }
                            }
                            else if(serviceType == ServiceType.dataRefactor){

                            }
                        }
                    });
                };
                polling();
            }
        },

        // update data state
        onReceivedDataDownloaded: function (taskID, taskData) {
            var self = this;
            var state = null;
            // if(!replyData.err){
            state = DataState.received;
            // }
            // else{
            //     state = DataState.failed;
            // }
            taskData.state = state;
            TaskInstanceManager.updateDataState(taskID, taskData.gdid, state,function (err,rst) {
                if(err){
                    err.place = 'updateDataState';
                }
                WebSocketCtrl.emit(taskID, 'data downloaded', JSON.stringify({error:err,downloadRst:taskData}));
                if(!err) {
                    // TODO 有时没有触发！
                    self.checkMSState(taskID,taskData.gdid,taskData.MSID);
                }
            });
        },

        // 有待重写！应该在创建task时将所有event都加进来，没有数据的gdid为空
        // 先暂时不管多state的情况，只有所有state的数据准备好了才能运行
        checkMSState: function (taskID,gdid, MSinsID, getStateFlag) {


            var self = this;
            // var MSinsID = null;     // 一个ms可能会有多个实例
            var task = TaskInstanceManager.get(taskID);
            if(task){
                var dataList = [];
                dataList = task.taskCfg.dataList;
                if(!MSinsID){
                    for(let i=0;i<dataList.length;i++){
                        if(dataList[i].gdid == gdid){
                            if(dataList[i].isMid == null || dataList[i].isMid == false){
                                MSinsID = dataList[i].MSID;
                                break;
                            }
                        }
                    }
                }
                if(MSinsID){
                    var msState = null;
                    var msStateList = task.MSState;
                    for(let i=0;i<msStateList.length;i++){
                        if(msStateList[i].MSID == MSinsID){
                            msState = msStateList[i];
                            break;
                        }
                    }

                    // deprecated
                    // let uploadInputList = [];
                    // for(let i=0;i<dataList.length;i++){
                    //     if(dataList[i].MSID == MSinsID){
                    //         uploadInputList.push(dataList[i]);
                    //     }
                    // }
                    //
                    // TaskInstanceManager.getServiceByID(taskID, MSinsID,function (err, service) {
                    //     if(err){
                    //         err.place = 'getServiceByID checkMSState';
                    //         if(getStateFlag){
                    //             return false;
                    //         }
                    //         else{
                    //             return WebSocketCtrl.emit(taskID,'error',JSON.stringify({error:err}));
                    //         }
                    //     }
                    //     else{
                    //         if(service.serviceType == ServiceType.model){
                    //             var msInputList = [];
                    //             var msOutputList = [];
                    //             var isMSReady = true;
                    //             var mdlEvent = __getServiceEvents(service);
                    //             // 判断模型数据是否准备好，并组织输入输出
                    //             for(let i=0;i<mdlEvent.length;i++){
                    //                 var isDataReady = false;
                    //                 if(mdlEvent[i]._$.type == 'response'){
                    //                     var hasUploaded = false;
                    //                     var isOptional = CommonMethod.isTrue(mdlEvent[i]._$.optional);
                    //                     msInputList.push({
                    //                         DataId: '',
                    //                         Event: mdlEvent[i]._$.name,
                    //                         Optional: isOptional?1:0,
                    //                         StateId: mdlEvent[i].stateID,
                    //                         StateName: mdlEvent[i].stateName,
                    //                         StateDes: mdlEvent[i].stateDes
                    //                     });
                    //
                    //                     for(let j=0;j<uploadInputList.length;j++){
                    //                         if(mdlEvent[i].stateID == uploadInputList[j].stateID && mdlEvent[i]._$.name == uploadInputList[j].eventName){
                    //                             hasUploaded = true;
                    //                             // 可选数据对模型准备状态的控制
                    //                             // if(isOptional){
                    //                             //     if(uploadInputList[j].state == DataState.received){
                    //                             //         msInputList[msInputList.length-1].DataId = uploadInputList[j].gdid;
                    //                             //         msInputList[msInputList.length-1].Tag = uploadInputList[j].fname;
                    //                             //         isDataReady = true;
                    //                             //         break;
                    //                             //     }
                    //                             //     else{
                    //                             //         isDataReady = false;
                    //                             //         break;
                    //                             //     }
                    //                             // }
                    //
                    //                             if(uploadInputList[j].state == DataState.received){
                    //                                 msInputList[msInputList.length-1].DataId = uploadInputList[j].gdid;
                    //                                 msInputList[msInputList.length-1].Tag = uploadInputList[j].fname;
                    //                                 isDataReady = true;
                    //                                 break;
                    //                             }
                    //                             else{
                    //                                 isDataReady = false;
                    //                                 break;
                    //                             }
                    //                         }
                    //                     }
                    //
                    //                     if(isOptional && !hasUploaded){
                    //                         isDataReady = true;
                    //                         break;
                    //                     }
                    //                 }
                    //                 else if(mdlEvent[i]._$.type == 'noresponse'){
                    //                     msOutputList.push({
                    //                         // DataId: eventList[i].gdid,
                    //                         // Optional: eventList[i]._$.optional,
                    //                         StateName: mdlEvent[i].stateName,
                    //                         StateDes: mdlEvent[i].stateDes,
                    //                         StateId: mdlEvent[i].stateID,
                    //                         Event: mdlEvent[i]._$.name,
                    //                         Tag:''
                    //                     });
                    //                     isDataReady = true;
                    //                 }
                    //
                    //
                    //                 // deprecated可选数据对模型准备状态的控制
                    //                 // var isOptional = CommonMethod.isTrue(eventList[i]._$.optional);
                    //                 // if(eventList[i]._$.type == 'response' && isOptional){
                    //                 //     var fromNode = __getFromNodeEvent(task.solution,MSinsID, eventList[i].stateID, eventList[i]._$.name);
                    //                 //     if(!fromNode){
                    //                 //         isDataReady = true;
                    //                 //     }
                    //                 //
                    //                 //     for(let j=0;j<inputEvents.length;j++){
                    //                 //         if(eventList[i].stateID == inputEvents[j].stateID && eventList[i]._$.name == inputEvents[j].eventName){
                    //                 //             if(inputEvents[j].state == DataState.received){
                    //                 //                 inputData[inputData.length-1].DataId = inputEvents[j].gdid;
                    //                 //                 inputData[inputData.length-1].Tag = inputEvents[j].fname;
                    //                 //                 isDataReady = true;
                    //                 //                 break;
                    //                 //             }
                    //                 //             else{
                    //                 //                 isDataReady = false;
                    //                 //                 break;
                    //                 //             }
                    //                 //         }
                    //                 //     }
                    //                 // }
                    //
                    //                 if(!isDataReady){
                    //                     isMSReady = false;
                    //                     break;
                    //                 }
                    //             }
                    //             msState.taskStateFlag = 1;
                    //             self.checkTaskState(task._id);
                    //             if(isMSReady){
                    //                 if(getStateFlag){
                    //                     return true;
                    //                 }
                    //                 else{
                    //                     self.emitMSReady(taskID,MSinsID,msInputList,msOutputList);
                    //                 }
                    //             }
                    //             else{
                    //                 return false;
                    //             }
                    //         }
                    //         else if(service.serviceType == ServiceType.dataMap){
                    //             var inputData = [];
                    //             var outputData = [];
                    //             var isMSReady = true;
                    //             var state = service.CDL.StateGroup.States[0];
                    //             var eventList = state.Events;
                    //             // 判断模型数据是否准备好，并组织输入输出
                    //             for(let i=0;i<eventList.length;i++){
                    //                 var isDataReady = false;
                    //                 if(eventList[i].type == 'in'){
                    //                     inputData.push({
                    //                         DataId: '',
                    //                         Event: eventList[i].name,
                    //                         Optional: eventList[i].optional,
                    //                         StateId: state.id
                    //                     });
                    //                     for(let j=0;j<uploadInputList.length;j++){
                    //                         if(state.id == uploadInputList[j].stateID && eventList[i].name == uploadInputList[j].eventName){
                    //                             if(uploadInputList[j].state == DataState.received){
                    //                                 inputData[inputData.length-1].DataId = uploadInputList[j].oid;
                    //                                 inputData[inputData.length-1].fname = uploadInputList[j].fname;
                    //                                 isDataReady = true;
                    //                                 break;
                    //                             }
                    //                             else{
                    //                                 isDataReady = false;
                    //                                 break;
                    //                             }
                    //                         }
                    //                     }
                    //                 }
                    //                 else if(eventList[i].type == 'out'){
                    //                     outputData.push({
                    //                         // DataId: eventList[i].gdid,
                    //                         // Optional: eventList[i]._$.optional,
                    //                         StateId: state.id,
                    //                         Event: eventList[i].name,
                    //                         Tag:''
                    //                     });
                    //                     isDataReady = true;
                    //                 }
                    //                 if(eventList[i].type == 'in' && (eventList[i].optional == '1' || eventList[i].optional == 'true')){
                    //                     var fromNode = __getFromNodeEvent(task.solution,MSinsID, eventList[i].stateID, eventList[i]._$.name);
                    //                     if(!fromNode){
                    //                         isDataReady = true;
                    //                     }
                    //                 }
                    //                 if(!isDataReady){
                    //                     isMSReady = false;
                    //                     break;
                    //                 }
                    //             }
                    //             msState.taskStateFlag = 1;
                    //             self.checkTaskState(task._id);
                    //             if(isMSReady){
                    //                 if(getStateFlag){
                    //                     return true;
                    //                 }
                    //                 else{
                    //                     self.emitMSReady(taskID,MSinsID,inputData,outputData);
                    //                 }
                    //             }
                    //             else{
                    //                 return false;
                    //             }
                    //         }
                    //         else if(service.serviceType == ServiceType.dataRefactor){
                    //
                    //         }
                    //     }
                    // });
                    // TODO msid err
                    var serviceDriver = __getServiceDriver(taskID,MSinsID);
                    if(serviceDriver.ready){
                        self.emitMSReady(taskID,MSinsID,serviceDriver.inputData,serviceDriver.outputData);
                        return true;
                    }
                    else{
                        return false;
                    }
                }
                else{
                    if(getStateFlag){
                        return false;
                    }
                    else{
                        return WebSocketCtrl.emit(taskID,'error',JSON.stringify({
                            error: {
                                message:'Can\'t find the related model service!',
                                place: 'checkMSState'
                            }
                        }));
                    }
                }
            }
            else{
                if(getStateFlag){
                    return false;
                }
                else{
                    return WebSocketCtrl.emit(taskID,'error',JSON.stringify({
                        error: {
                            message:'Can\'t find the related task!',
                            place: 'checkMSState'
                        }
                    }));
                }
            }
        },

        // update MS state, emit ms ready
        emitMSReady: function (taskID,MSinsID,inputData,outputData) {
            var self = this;
            TaskInstanceManager.updateMSState(taskID,MSinsID,MSState.pending,function (err, rst) {
                if(err){
                    err.place = 'emitMSReady';
                    return WebSocketCtrl.emit(taskID,'error',JSON.stringify({error:err}));
                }
                else{
                    WebSocketCtrl.emit(taskID,'service starting',JSON.stringify({
                        error:null,
                        MSinsID: MSinsID
                    }));
                    TaskInstanceManager.getServiceByID(taskID, MSinsID, function (err, service) {
                        if(err){
                            return WebSocketCtrl.emit(taskID,'error',JSON.stringify({error: err}));
                        }
                        else if(service.serviceType == ServiceType.model){
                            let host = service.host;
                            let port = service.port;
                            let url = 'http://' + host + ':' + port + '/modelser/' + service.MS._id;
                            let form = {
                                ac: 'run',
                                // msid: service.MS._id,
                                inputdata: inputData,
                                outputdata: outputData
                                // centerHost: app.centerHost,
                                // centerPort: setting.port,
                                // taskID: taskID,
                                // MSinsID: MSinsID
                            };
                            RmtReqCtrl.getByServer(url,form,function (err, res) {
                                if(err){
                                    // TODO 重试
                                }
                                else{
                                    if(typeof res == 'string'){
                                        res = JSON.parse(res);
                                    }

                                    var state = null;
                                    if(res.res == 'suc'){
                                        state = MSState.running;
                                    }
                                    else{
                                        res.error.place = 'starting service';
                                        state = MSState.collapsed;
                                    }
                                    WebSocketCtrl.emit(taskID,'service started',JSON.stringify({
                                        error:res.error,
                                        MSinsID: MSinsID
                                    }));
                                    TaskInstanceManager.updateMSState(taskID, MSinsID, state, function (err,rst) {
                                        if(err){
                                            err.place = 'updateMSState emitMSReady';
                                            return WebSocketCtrl.emit(taskID,'error',JSON.stringify({error:err}));
                                        }
                                        var msrID = res.msr_id;
                                        self.getRunRst({
                                            taskID: taskID,
                                            MSinsID: MSinsID,
                                            serviceType: service.serviceType,
                                            msrID: msrID,
                                            host: host,
                                            port: port
                                        });
                                    })
                                }
                            });
                        }
                        else if(service.serviceType == ServiceType.dataMap){
                            let host = service.host;
                            let port = service.port;
                            let url = 'http://' + host + ':' + port + '/datamap/use/call';
                            let form = {
                                id: service.DS._id,
                                username: 'admin',
                                // callType: service.callType,
                                callType: service.callType,
                                in_oid: inputData[0].DataId,
                                in_fillname: inputData[0].fname,
                                out_dir: '598844df055f5749846f44fc',
                                out_filename:  new ObjectId() + '.xml'
                            };
                            RmtReqCtrl.getByServer(url,form,function (err, res) {
                                if(err){
                                    // TODO 重试
                                }
                                else{
                                    var msrID = res;
                                    var state = MSState.running;
                                    WebSocketCtrl.emit(taskID,'service started',JSON.stringify({
                                        error:res.error,
                                        MSinsID: MSinsID
                                    }));
                                    TaskInstanceManager.updateMSState(taskID, MSinsID, state, function (err,rst) {
                                        if(err){
                                            err.place = 'updateMSState emitMSReady';
                                            return WebSocketCtrl.emit(taskID,'error',JSON.stringify({error:err}));
                                        }
                                        self.getRunRst({
                                            taskID: taskID,
                                            MSinsID: MSinsID,
                                            serviceType: service.serviceType,
                                            msrID: msrID,
                                            host: host,
                                            port: port
                                        });
                                    });
                                }
                            })
                        }
                        else if(service.serviceType == ServiceType.dataRefactor){

                        }
                    });
                }
            })
        },
        
        getRunRst: function (msrInfo) {
            var self = this;
            var url = null;
            var polling = null;
            if(msrInfo.serviceType == ServiceType.model){
                url = 'http://' + msrInfo.host + ':' + msrInfo.port + '/modelserrun/json/' + msrInfo.msrID;
                polling = function () {
                    RmtReqCtrl.getByServer(url, null, function (err,res) {
                        if(err){
                            // TODO
                        }
                        else{
                            if(typeof res == 'string'){
                                res = JSON.parse(res);
                            }
                            if(res.result == 'err'){
                                // polling();
                                console.log(res.message);
                            }
                            else if(res.result == 'suc'){
                                var msr = res.data;
                                if(msr.msr_time != 0){
                                    var finishInfo = {
                                        taskID: msrInfo.taskID,
                                        MSinsID: msrInfo.MSinsID,
                                        host: msrInfo.host,
                                        port: msrInfo.port,
                                        serviceType: ServiceType.model
                                    };
                                    if(msr.msr_status == 1){
                                        finishInfo.MSState = MSState.finished;
                                        finishInfo.outputData = msr.msr_output;
                                        for(let i=0;i<finishInfo.outputData.length;i++){
                                            finishInfo.outputData[i].posType = DataPositionType.modelservice;
                                        }
                                    }
                                    else if(msr.msr_status == -1){
                                        finishInfo.MSState = MSState.collapsed;
                                    }
                                    self.onReceivedMSFinished(finishInfo);
                                }
                                else{
                                    setTimeout(polling,5000);
                                }
                            }
                        }
                    });
                };
                polling();
            }
            else if(msrInfo.serviceType == ServiceType.dataRefactor){
                // url = 'http://' + msrInfo.host + ':' + msrInfo.port + '/modelserrun/json/' + msrInfo.msrID;
            }
            else if(msrInfo.serviceType == ServiceType.dataMap){
                url = 'http://' + msrInfo.host + ':' + msrInfo.port + '/common/records';
                var query = {
                    type: 'datamap',
                    guid: msrInfo.msrID
                };
                url += '?' + qs.stringify(query);

                TaskInstanceManager.getServiceByID(msrInfo.taskID, msrInfo.MSinsID, function (err, service) {
                    if (err) {
                        return WebSocketCtrl.emit(taskID, 'error', JSON.stringify({error: err}));
                    }
                    else{
                        polling = function () {
                            RmtReqCtrl.getByServer(url, null, function (err,res) {
                                if(err){
                                    // TODO
                                }
                                else{
                                    if(res == '[]' || res == ''){
                                        setTimeout(polling,5000);
                                    }
                                    else{
                                        var event = null;
                                        var state = service.CDL.StateGroup.States[0];
                                        var events = state.Events;
                                        for(let i=0;i< events.length; i++){
                                            if(events[i].type == 'out'){
                                                event = events[i];
                                                break;
                                            }
                                        }

                                        res = JSON.parse(res);
                                        var msr = res[0];
                                        var finishInfo = {
                                            taskID: msrInfo.taskID,
                                            MSinsID: msrInfo.MSinsID,
                                            host: msrInfo.host,
                                            port: msrInfo.port,
                                            serviceType: ServiceType.dataMap
                                        };
                                        if(msr.status == '1'){
                                            finishInfo.MSState = MSState.finished;
                                            finishInfo.outputData = [{
                                                StateId:state.id,
                                                Event: event.name,
                                                DataId: 'gd_' + uuid.v1(),
                                                oid: msr.output[0].oid,
                                                filename: msr.output[0].filename,
                                                posType: DataPositionType.dataservice
                                            }];
                                        }
                                        else{
                                            finishInfo.MSState = MSState.collapsed;
                                        }
                                        self.onReceivedMSFinished(finishInfo);
                                    }
                                }
                            });
                        };
                        polling();
                    }
                });
            }
        },

        // update MSState TaskState, dispatch data
        onReceivedMSFinished: function (finishedInfo) {
            var self = this;
            var task = TaskInstanceManager.get(finishedInfo.taskID);
            var serviceType = finishedInfo.serviceType;
            TaskInstanceManager.updateMSState(finishedInfo.taskID, finishedInfo.MSinsID, finishedInfo.MSState, function (err, rst) {
                if(err){
                    err.place = 'updateMSState onReceivedMSFinished';
                    return WebSocketCtrl.emit(task._id, 'error', JSON.stringify({error: err}));
                }
                else {
                    if(finishedInfo.MSState == MSState.collapsed){
                        // var taskState = __getTaskState(task);
                        // task.taskState = taskState;
                        TaskInstanceManager.update(task,function (err, rst) {
                            if (err) {
                                err.place = 'update onReceivedMSFinished';
                                return WebSocketCtrl.emit(task._id, 'error', JSON.stringify({error: err}));
                            }
                            else{
                                WebSocketCtrl.emit(task._id,'service stoped',JSON.stringify({
                                    error:null,
                                    MSinsID: finishedInfo.MSinsID,
                                    MSState: finishedInfo.MSState,
                                    newDataList: []
                                }));
                                self.init(task);
                                return ;
                            }
                        });
                    }
                    else{
                        var newDataList = [];
                        for(let i =0;i<finishedInfo.outputData.length;i++){
                            var output = finishedInfo.outputData[i];
                            var toNodes = __get2NodesEvent(task.solution,finishedInfo.MSinsID,output.StateId,output.Event);
                            let newData = {
                                host: finishedInfo.host,
                                port: finishedInfo.port,
                                state: DataState.received,
                                eventName: output.Event,
                                stateID: output.StateId,
                                MSID: finishedInfo.MSinsID,
                                gdid: output.DataId,
                                isInput: false,
                                posType: output.posType
                            };
                            if(serviceType == ServiceType.dataMap){
                                newData.oid = output.oid;
                                newData.fname = output.filename;
                            }
                            else if(serviceType == ServiceType.model){

                            }
                            else if(serviceType == ServiceType.dataRefactor){

                            }

                            task.taskCfg.dataList.push(newData);
                            newDataList.push(newData);
                            // 有多个实体
                            if(toNodes.length){
                                // TaskInstanceManager.getServiceByID(task._id, toNode.MSID, function (err, service) {
                                //     if(err){
                                //
                                //     }
                                //     else{
                                for(let j=0;j<toNodes.length;j++){
                                    var toNode = toNodes[j];
                                    newData.isMid = true;
                                    newData = {
                                        host: finishedInfo.host,
                                        port: finishedInfo.port,
                                        state: DataState.ready,
                                        eventName: toNode.eventName,
                                        stateID: toNode.stateID,
                                        MSID: toNode.MSID,
                                        gdid: output.DataId,
                                        isMid: false,
                                        isInput: false,
                                        posType: output.posType
                                    };
                                    if(serviceType == ServiceType.dataMap){
                                        newData.oid = output.oid;
                                        newData.fname = output.filename;
                                    }
                                    else if(serviceType == ServiceType.model){

                                    }
                                    else if(serviceType == ServiceType.dataRefactor){

                                    }
                                    task.taskCfg.dataList.push(newData);
                                    newDataList.push(newData);
                                }
                                    // }
                                // });
                            }
                            else{
                                newData.isMid = false;
                            }
                        }
                        // 程序如果在这里崩了怎么办？数据没更新，重新运行task时没有数据驱动
                        TaskInstanceManager.update(task,function (err, rst) {
                            if(err){
                                err.place = 'update onReceivedMSFinished';
                                return WebSocketCtrl.emit(task._id,'error',JSON.stringify({error:err}));
                            }
                            else{
                                // var taskState = __getTaskState(task);
                                // task.taskState = taskState;
                                TaskInstanceManager.update(task,function (err, rst) {
                                    if (err) {
                                        err.place = 'update onReceivedMSFinished';
                                        return WebSocketCtrl.emit(task._id, 'error', JSON.stringify({error: err}));
                                    }
                                    else{
                                        WebSocketCtrl.emit(task._id,'service stoped',JSON.stringify({
                                            error:null,
                                            MSinsID: finishedInfo.MSinsID,
                                            MSState: finishedInfo.MSState,
                                            newDataList: newDataList
                                        }));
                                        self.init(task);
                                    }
                                })
                            }
                        });
                    }
                }
            });
        }
    };
})();